#include "matplotlibcpp.h"
#include <cmath>
#include <vector>
#include "SplineCurveFit.hpp"
#include <iostream>

const double PI = acos(-1);

using namespace std;
namespace plt = matplotlibcpp;

// 计算心形曲线
void heartshape(){
    double rt3 = sqrt(3);
    //double x = -1 * rt3 * cos(t*2*PI);
    //double y = 2./3*(rt3 * sin(2*PI*t) + sqrt(std::abs(rt3*cos(2*PI*t))));

    // for (double t = 0; t <= 1; t+=1.0/500) {
    //     xData.push_back(-1 * rt3 * cos(t*2*PI));
    //     yData.push_back(2./3*(rt3 * sin(2*PI*t) + sqrt(std::abs(rt3*cos(2*PI*t)))));
    // }
    vector<int> num_of_points = {10,40,160};
    vector<string> file_name = {"../figure/heart_10.png","../figure/heart_40.png", "../figure/heart_160.png"};
    // 计算曲线差值点
    for (int j=0; j<3; j++) {
        vector<double> xData, yData;
        int num = num_of_points[j];
        for (int i=0; i<num; i++) {
            double t = i*1./(num-1);
            xData.push_back(rt3 * sin(t * 2 * PI));
            yData.push_back(2. / 3 *(rt3 * cos(2 * PI * t) + sqrt(std::abs(rt3 * sin(2 * PI * t)))));
        }

        vector<double> x, y;  // 累计弦长的曲线
        vector<double> x_eq, y_eq;  // 等距节点的曲线
        SplineCurveFit curve(xData, yData);
        
        curve.setKnotsType(SplineCurveFit::equaldistance);
        curve.setupCurve();
        for (double t = 0; t <= 1; t+=1.0/1000) {
            vector<double> point = curve.interpolate(t);
            x_eq.push_back(point[0]);
            y_eq.push_back(point[1]);
        }
        curve.setKnotsType(SplineCurveFit::cumulative);
        curve.setupCurve();
        for (double t = 0; t <= 1; t+=1.0/1000) {
            vector<double> point = curve.interpolate(t);
            x.push_back(point[0]);
            y.push_back(point[1]);
        }

        plt::figure_size(1200, 700);
        plt::plot(x,y);
        plt::plot(x_eq, y_eq, "r--");
        plt::plot(xData, yData, "o");
        plt::save(file_name[j]);
    }
}

// 计算二维曲线
// (sint + tcost, cost - tsint) t \in [0, 6PI]
void curve_r2(){
    vector<double> x, y;
    for (double t=0; t<=6; t+=0.01) {
        x.push_back(sin(t*PI) + t*PI*cos(t*PI));
        y.push_back(cos(t*PI) - t*PI*sin(t*PI));
    }

    vector<double> xData, yData;
    int num = 20;
    for (int i=0; i<num; i++) {
        double t = 6.0*i/(num-1);
        xData.push_back(sin(t*PI) + t*PI*cos(t*PI));
        yData.push_back(cos(t*PI) - t*PI*sin(t*PI));    
    }

    SplineCurveFit curve(xData, yData);
    curve.setKnotsType(SplineCurveFit::cumulative);
    curve.setupCurve();
    vector<double> x_c, y_c;
    for (double t=0; t<=1; t+=0.001) {
        vector<double> point = curve.interpolate(t);
        x_c.push_back(point[0]);
        y_c.push_back(point[1]);
    }

    curve.setKnotsType(SplineCurveFit::equaldistance);
    curve.setupCurve();
    vector<double> x_eq, y_eq;
    for (double t=0; t<=1; t+=0.001) {
        vector<double> point = curve.interpolate(t);
        x_eq.push_back(point[0]);
        y_eq.push_back(point[1]);
    }

    plt::figure_size(1200, 700);
    plt::plot(x, y, "b--");
    plt::plot(x_c, y_c, "r");
    plt::plot(x_eq,y_eq,"g");
    plt::save("../figure/E_r2.png");

}

// 计算球面样条
// (sin ut*cos vt, sin ut*sin vt, cos ut), ut=cost, vt=sint, t \in [0, 2PI]
void curve_r3(){
    vector<double> x, y, z;
    for (double t=0; t<=2; t+=0.001) {
        x.push_back(sin(cos(t*PI))*cos(sin(t*PI)));
        y.push_back(sin(cos(t*PI))*sin(sin(t*PI)));
        z.push_back(cos(cos(t*PI)));
    }

    vector<double> xData, yData, zData;
    int num = 40;
    for (int i=0; i<num; i++) {
        double t = 2.0*i/(num-1);
        xData.push_back(sin(cos(t*PI))*cos(sin(t*PI)));
        yData.push_back(sin(cos(t*PI))*sin(sin(t*PI)));
        zData.push_back(cos(cos(t*PI)));   
    }

    SplineCurveFit curve(xData, yData, zData);
    curve.setupBallCurve();

    vector<double> x_c, y_c, z_c;
    for (double t=0; t<=1; t+=0.001) {
        vector<double> point = curve.interpolate(t);
        x_c.push_back(point[0]);
        y_c.push_back(point[1]);
        z_c.push_back(point[2]);
    }  

    plt::figure_size(1200, 700);
    plt::plot3(x, y, z);
    plt::save("../figure/E_standard_r3.png");
    plt::figure_size(1200, 700);
    plt::plot3(x_c, y_c, z_c);
    plt::save("../figure/E_r3.png");

}

int main() {
    std::cout << "----- running E -----" << std::endl;
    heartshape();
    curve_r2();
    curve_r3();
    std::cout << "----- complete E -----" << std::endl;
}